/*
 * Copyright (c) 2024-2025 ziduo.xyz.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "string.h"
#include "common_def.h"
#include "osal_debug.h"
#include "osal_task.h"
#include "cmsis_os2.h"
#include "securec.h"
#include "sle_device_discovery.h"
#include "sle_connection_manager.h"
#include "sle_ssap_client.h"
#include "sle_errcode.h"
#include "ohos_init.h"
#include "ohos_sle_common.h"
#include "ohos_sle_errcode.h"
#include "ohos_sle_ssap_server.h"
#include "ohos_sle_ssap_client.h"
#include "ohos_sle_device_discovery.h"
#include "ohos_sle_connection_manager.h"
#include "iot_uart.h"
#include "pinctrl.h"
#include "uart.h"
#include "errcode.h"


#define printf(fmt, args...) printf(fmt, ##args)

// 应用的串口数据接收缓冲区大小
#define APP_CLIENT_UART_TRANSFER_BUFF_SIZE          256

// SLE 任务的延时
#define SLE_TASK_DELAY_1000MS                       1000

// SLE 扫描间隔和窗口
#define SLE_SEEK_INTERVAL_DEFAULT                   100
#define SLE_SEEK_WINDOW_DEFAULT                     100
// SLE MTU
#define SLE_MTU_SIZE_DEFAULT                        520
// SLE 数据发送缓冲长度，发送数据时的最大长度
#define APP_CLIENT_BLE_SEND_BUFF_SIZE               520 /* max length. */

// 服务名称
#ifndef APP_SERVER_SLE_NAME
#define APP_SERVER_SLE_NAME "lap_counter_ser"
#endif



// 本方 ID
uint8_t g_app_client_id = 0;

// 串口接收缓冲区
static uint8_t g_app_client_uart_rx_buff[APP_CLIENT_UART_TRANSFER_BUFF_SIZE] = { 0 };

// 串口接收缓冲区配置
static uart_buffer_config_t g_app_client_uart_buffer_config = {
    .rx_buffer = g_app_client_uart_rx_buff,                     // 缓冲区
    .rx_buffer_size = APP_CLIENT_UART_TRANSFER_BUFF_SIZE        // 缓冲区大小
};


// SLE 发送缓冲区
uint8_t ble_send_buf[APP_CLIENT_BLE_SEND_BUFF_SIZE] = { 0 };

// 客户端 SLE UUID
static char g_sle_uuid_app_client[] = { 0x39, 0xBE, 0xA8, 0x80, 0xFC, 0x70, 0x11, 0xEA, 
    0xB7, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    
// 客户端 SLE 连接 ID
uint16_t g_app_client_sle_conn_id = 0;

// 保存远端 SLE 地址
static SleAddr g_app_client_sle_remote_addr = { 0 };

// 客户端 SLE 的扫描回调函数集合
static sle_announce_seek_callbacks_t g_app_client_sle_seek_cbk = { 0 };

// 客户端 SLE 连接的回调函数集合
static SleConnectionCallbacks g_app_client_sle_connect_cbk = { 0 };

// 客户端 ssapc 回调函数集合
static ssapc_callbacks_t g_app_client_sle_ssapc_cbk = { 0 };

// 保存发现的服务
static ssapc_find_service_result_t g_app_client_sle_find_service_result = { 0 };

// 保存客户端 SLE 发送相关参数
ssapc_write_param_t g_app_client_sle_send_param = { 0 };



// SLE 指示事件上报钩子，用于向服务端发送数据
// 参数：本地id，连接id，
// ssapc_handle_value_t:
//      uint16_t handle; 属性句柄
//      uint8_t  type; 属性类型
//      uint16_t data_len; 数据长度
//      uint8_t  *data; 数据内容
void ssapc_indication_callbacks(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
            errcode_t status){
    (void)client_id;
    (void)conn_id;
    (void)data;
    (void)status;
}


// SLE 通知事件上报钩子，用于接收服务端发送来的数据
// 参数：本地id，连接id，
// ssapc_handle_value_t:
//      uint16_t handle; 属性句柄
//      uint8_t  type; 属性类型
//      uint16_t data_len; 数据长度
//      uint8_t  *data; 数据内容
void ssapc_notification_callbacks(uint8_t client_id, uint16_t conn_id, ssapc_handle_value_t *data,
            errcode_t status){
    (void)client_id;
    (void)conn_id;
    (void)status;
    
        data->data[data->data_len -1] = '\0';
        printf("]lc>: %s\r\n",data->data);     
}


// 收到写响应回调函数
static void app_client_write_cfm_cb(uint8_t client_id, uint16_t conn_id,
                                                ssapc_write_result_t *write_result, errcode_t status)
{
    printf("\r\n[%s] write cfm, client id:%d, conn_id:%d, status:%d, handle:%02x, type:%02x\r\n", __func__,
                client_id, conn_id, status, write_result->handle, write_result->type);
}


// 客户端发现服务完成回调函数
static void app_client_find_structure_cmp_cbk(uint8_t client_id, uint16_t conn_id,
            ssapc_find_structure_result_t *structure_result, errcode_t status)
{
    printf("\r\n[%s] find structure complete, client id:%d, conn_id:%d, status:%d, type:%d, uuid len:%d\r\n", __func__,
                client_id, conn_id, status, structure_result->type, structure_result->uuid.len);
}


// 客户端发现特征回调函数
// ssapc_find_property_result_t:
//      uint16_t   handle; 特征句柄
//      uint32_t   operate_indication; 操作指示
//      sle_uuid_t uuid; 特征uuid
//      uint8_t    descriptors_count; 特征描述符类型列表长度
//      uint8_t    descriptors_type[0]; 特征描述符类型列表
static void app_client_find_property_cbk(uint8_t client_id, uint16_t conn_id,
            ssapc_find_property_result_t *property, errcode_t status)
{
    printf("\r\n[%s] find property, client id: %d, conn id: %d, operate ind: %d, "
                "descriptors count: %d, status:%d, property->handle %d\r\n", __func__,
                client_id, conn_id, property->operate_indication,
                property->descriptors_count, status, property->handle);
                
    // 保存发送参数
    g_app_client_sle_send_param.handle = property->handle;
    g_app_client_sle_send_param.type = SSAP_PROPERTY_TYPE_VALUE;
}


// 客户端发现服务回调函数
// ssapc_find_service_result_t:
//      uint16_t   start_hdl; 服务起始句柄
//      uint16_t   end_hdl; 服务结束句柄
//      sle_uuid_t uuid; 服务uuid
static void app_client_find_structure_cbk(uint8_t client_id, uint16_t conn_id,
            ssapc_find_service_result_t *service,
            errcode_t status)
{
    printf("\r\n[%s] find structure cbk, client id: %d, conn_id:%d, status:%d\r\n", __func__,
                client_id, conn_id, status);
    printf("\r\n[%s] find structure start_hdl:[0x%02x], end_hdl:[0x%02x], uuid len:%d\r\n", __func__,
                service->start_hdl, service->end_hdl, service->uuid.len);
                
    // 保存发现的服务数据：起始句柄，结束句柄，uuid
    g_app_client_sle_find_service_result.start_hdl = service->start_hdl;
    g_app_client_sle_find_service_result.end_hdl = service->end_hdl;
    memcpy_s(&g_app_client_sle_find_service_result.uuid, sizeof(sle_uuid_t), &service->uuid, sizeof(sle_uuid_t));
}


// 客户端 MTU 大小改变回调函数
// 参数：本地id，连接id，修改后的MTU信息，错误码
// ssap_exchange_info_t:
//      uint32_t mtu_size; MTU 大小
//      uint16_t version; 版本
// ssapc_find_structure_param_t
//      uint8_t    type; 查找类型
//      uint16_t   start_hdl; 起始句柄
//      uint16_t   end_hdl; 结束句柄
//      sle_uuid_t uuid; 按uuid查找，注：按照uuid查找时生效，其余不生效
static void app_client_sle_exchange_info_cbk(uint8_t client_id, uint16_t conn_id, ssap_exchange_info_t *param,
            errcode_t status)
{
    printf("\r\n[%s] pair complete, client id: %d, conn id: %d, status:%d\r\n", __func__, client_id, conn_id, status);
    printf("\r\n[%s] mtu exchange, mtu size: %d, version: %d.\r\n", __func__, 
                param->mtu_size, param->version);
                
    // 开始搜索服务
    ssapc_find_structure_param_t find_param = { 0 };
    find_param.type = 1;                                                // 服务类型
    find_param.start_hdl = 1;                                           // 起始句柄
    find_param.end_hdl = 0xFFFF;                                        // 结束句柄
    int ret =  ssapc_find_structure(client_id, conn_id, &find_param);

    printf("\r\n[%s] ssapc_find_structure errcode = %d\r\n", __func__, ret);
}


// 客户端 SLE 连接状态改变回调函数
// 参数：连接id，远端地址，连接状态，配对状态， 断开原因
// SleAcbStateType:
//      OH_SLE_ACB_STATE_NONE 未连接
//      OH_SLE_ACB_STATE_CONNECTED 已连接
//      OH_SLE_ACB_STATE_DISCONNECTED 已断开
// SleDiscReasonType:
//      OH_SLE_DISCONNECT_BY_REMOTE 远端断开
//      OH_SLE_DISCONNECT_BY_LOCAL 本端断开
static void app_client_connect_state_changed_cbk(uint16_t conn_id, const SleAddr *addr,
            SleAcbStateType conn_state, SlePairStateType pair_state, SleDiscReasonType disc_reason)
{
    unused(addr);
    unused(pair_state);
    printf("\r\n[%s] client sle conn state changed disc_reason:0x%x\r\n", __func__, disc_reason);
    g_app_client_sle_conn_id = conn_id;
    
    if (conn_state == SLE_ACB_STATE_CONNECTED) { // 已连接状态
        printf("\r\n[%s] client sle conn state: connected.\r\n", __func__);
        
        // 修改 MTU
        SsapcExchangeInfo info = {0};
        info.mtuSize = SLE_MTU_SIZE_DEFAULT;
        info.version = 1;
        SsapcExchangeInfoReq(0, conn_id, &info);
        
        // 进行配对
        SlePairRemoteDevice(addr);
    } else if (conn_state == SLE_ACB_STATE_NONE) { // 未连接状态
        printf("\r\n[%s] client sle conn state: none.\r\n", __func__);
    } else if (conn_state == SLE_ACB_STATE_DISCONNECTED) { // 已断开状态
        printf("\r\n[%s] client sle conn state: disconnected.\r\n", __func__);
        
        // 移除配对
        SleRemovePairedRemoteDevice(addr);
        // 开始扫描
        app_client_sle_start_scan();
    }
}


// 客户端 SLE 扫描结果回调函数
// seek_result_data 扫描结果
// SleSeekResultInfo:
//      uint8_t eventType; 上报事件类型
//      SleAddr addr; 地址
//      SleAddr directAddr; 定向发现地址
//      uint8_t rssi; 信号强度指示，取值范围[-127dBm, 20dBm]，0x7F表示不提供信号强度指示
//      uint8_t dataStatus; 数据状态
//      uint8_t dataLength; 数据长度
//      uint8_t *data; 数据
// SleAddr:
//      uint8_t type; 地址类型
//      unsigned char addr[OH_SLE_ADDR_LEN]; SLE设备地址
static void app_client_seek_result_info_cbk(SleSeekResultInfo *seek_result_data)
{
    //printf("\r\n[%s] client sle seek data: data = %s\r\n", __func__, seek_result_data->data);
    
    if (seek_result_data == NULL) {
        printf("\r\n[%s] status error: seek_result_data == NULL\r\n", __func__);
    } else if (strstr((const char *)seek_result_data->data, APP_SERVER_SLE_NAME) != NULL) { // 如果数据中包含server的名字
        // printf("\r\n[%s] client sle seek addr: addr = %s\r\n", __func__, seek_result_data->addr.addr);
        memcpy_s(&g_app_client_sle_remote_addr, sizeof(sle_addr_t), &seek_result_data->addr, sizeof(sle_addr_t));
        // 停止扫描
        SleStopSeek();
    }
}


// 客户端关闭 SLE 扫描的回调函数
static void app_client_seek_disable_cbk(errcode_t status)
{
    if (status != 0) {
        printf("\r\n[%s] client sle seek disable err. errcode = %d\r\n", __func__, status);
    } else {
        // 连接远端设备
        SleConnectRemoteDevice(&g_app_client_sle_remote_addr);
    }
}


// 客户端 SLE 扫描打开的回调函数
static void app_client_seek_enable_cbk(errcode_t status)
{
    if (status != 0) {
        printf("\r\n[%s] client sle seek enable err. errcode = %d\r\n", __func__, status);
    }
}

// 客户端 SLE 开始扫描
void app_client_sle_start_scan(void)
{
    // SLE 扫描参数设置
    SleSeekParam param = { 0 };
    param.ownaddrtype = 0;                                  // 本地地址类型
    param.filterduplicates = 0;                             // 重复过滤开关 0关，1开
    param.seekfilterpolicy = 0;                             // 过滤类型
    param.seekphys = 1;                                     // 扫描设备使用的 PHY
    param.seekType[0] = 1;                                  // 扫描类型
    param.seekInterval[0] = SLE_SEEK_INTERVAL_DEFAULT;      // 扫描间隔 取值范围[0x0004, 0xFFFF]，time = N * 0.125ms
    param.seekWindow[0] = SLE_SEEK_WINDOW_DEFAULT;          // 扫描窗口 取值范围[0x0004, 0xFFFF]，time = N * 0.125ms
    
    // 设置扫描参数
    SleSetSeekParam(&param);
    
    // 开始扫描
    SleStartSeek();
}


// 客户端 SLE 打开的回调函数
static void app_client_sle_enable_cbk(errcode_t status)
{
    if (status != 0) {
        printf("\r\n[%s] client sle enable err. errcode = %d\r\n", __func__, status);
    } else {
        osal_msleep(SLE_TASK_DELAY_1000MS);
        // 开始扫描
        app_client_sle_start_scan();
    }
}


// 注册客户端 ssapc 相关回调函数
static void app_client_ssapc_cbk_register()
{
    g_app_client_sle_ssapc_cbk.exchange_info_cb = app_client_sle_exchange_info_cbk;         // MTU大小改变回调函数
    g_app_client_sle_ssapc_cbk.find_structure_cb = app_client_find_structure_cbk;           // 发现服务回调函数
    g_app_client_sle_ssapc_cbk.ssapc_find_property_cbk = app_client_find_property_cbk;      // 发现特征回调函数
    g_app_client_sle_ssapc_cbk.find_structure_cmp_cb = app_client_find_structure_cmp_cbk;   // 发现服务完成回调函数
    g_app_client_sle_ssapc_cbk.write_cfm_cb = app_client_write_cfm_cb;                      // 收到写响应回调函数
    g_app_client_sle_ssapc_cbk.notification_cb = ssapc_notification_callbacks;              // 通知事件上报钩子
    g_app_client_sle_ssapc_cbk.indication_cb = ssapc_indication_callbacks;                  // 指示事件上报钩子
    
    // 注册相关回调函数
    ssapc_register_callbacks(&g_app_client_sle_ssapc_cbk);
}


// 注册客户端 SLE 连接回调函数
static void app_client_sle_connect_cbk_register(void)
{
    g_app_client_sle_connect_cbk.connectStateChangedCb = app_client_connect_state_changed_cbk; // 连接状态改变回调函数
    SleConnectionRegisterCallbacks(&g_app_client_sle_connect_cbk);
}


// 注册扫描回调函数
static void app_client_sle_seek_cbk_register(void)
{
    g_app_client_sle_seek_cbk.sle_enable_cb = app_client_sle_enable_cbk;           // SLE打开的回调函数
    g_app_client_sle_seek_cbk.seek_enable_cb = app_client_seek_enable_cbk;         // SLE扫描打开的回调函数
    g_app_client_sle_seek_cbk.seek_result_cb = app_client_seek_result_info_cbk;    // SLE扫描结果的回调函数
    g_app_client_sle_seek_cbk.seek_disable_cb = app_client_seek_disable_cbk;       // SLE扫描关闭的回调函数
    
    // 注册回调函数集
    sle_announce_seek_register_callbacks(&g_app_client_sle_seek_cbk);
}


// 注册客户端 SLE
static errcode_t sle_uuid_client_register(void)
{
    errcode_t ret;
    SleUuid app_uuid = {0};

    printf("\r\n[%s] regist client sle.\r\n", __func__);
    app_uuid.len = sizeof(g_sle_uuid_app_client);
    if (memcpy_s(app_uuid.uuid, app_uuid.len, g_sle_uuid_app_client, sizeof(g_sle_uuid_app_client)) != EOK) {
        return ERRCODE_SLE_FAIL;
    }
    
    // 注册 ssapc client
    ret = SsapcRegisterClient(&app_uuid, &g_app_client_id);
    
    return ret;
}


// 客户端 SLE 初始化
void app_client_sle_init()
{
    // SLE的本地地址
    uint8_t local_addr[SLE_ADDR_LEN] = { 0x13, 0x67,0x5c, 0x07, 0x00, 0x51 };
    SleAddr local_address;
    local_address.type = 0;
    (void)memcpy_s(local_address.addr, SLE_ADDR_LEN, local_addr, SLE_ADDR_LEN);
    
    // 注册 SLE 客户端
    sle_uuid_client_register();
    
    // 注册 SLE 扫描回调函数
    app_client_sle_seek_cbk_register();
    
    // 注册 SLE 连接回调函数
    app_client_sle_connect_cbk_register();
    
    // 注册 ssapc 相关回调函数
    app_client_ssapc_cbk_register();
    
    // 开启 SLE
    EnableSle();
    
    // 设置 SLE 本地地址
	SleSetLocalAddr(&local_address);
    
}


// 设备通过handle向host发送数据
errcode_t app_client_send_data_use_sle_by_handle(const uint8_t *data, uint8_t len)
{
    // ssapc 写入参数
    ssapc_write_param_t param = {0};
   
    param.handle =  g_app_client_sle_find_service_result.start_hdl;     // 属性句柄
    param.type = 0;                                                     // 属性类型
    param.data = ble_send_buf;
    param.data_len = len + 1;
    if (memcpy_s(param.data, param.data_len, data, len) != EOK) {
        return ERRCODE_SLE_FAIL;
    }
   
   // 发起写请求
   // 参数：本方ID, SLE连接ID，写入的值
    int ret =SsapWriteReq(g_app_client_id, g_app_client_sle_conn_id, &param);
    return ret;
}


// 客户端通过SLE和服务端发送数据
int app_client_send_data_use_sle(uint8_t *data, uint8_t length){
    int ret;
    ret = app_client_send_data_use_sle_by_handle(data,length);
    return ret ;
}


// 串口数据接收回调函数
// 参数：接收缓冲区，接收长度，是否发生错误
// 如果在接收时未发生错误，则error为false，否则可能发生了校验、停止位、数据位的错误
static void app_client_uart_rx_callback(const void *buffer, uint16_t length, bool error)
{
    errcode_t ret;
   
    if(length > 0){
        // 将串口接收到的数据用SLE发送给服务端
        ret = app_client_send_data_use_sle((uint8_t *)buffer,(uint8_t)length);
        if(ret != 0){
            printf("\r\n[%s] sle client send data err: ret = %d\r\n", __func__, ret);
        }
    }

}


// 串口初始化
// 涉及的类型和方法位于：device/soc/hisilicon/ws63v100/sdk/include/driver/uart.h
static void app_client_uart_init(void)
{
    // 串口基本配置参数
    uart_attr_t attr = {
        .baud_rate = 115200,                // 波特率
        .data_bits = UART_DATA_BIT_8,       // 数据位
        .stop_bits = UART_STOP_BIT_1,       // 停止位
        .parity = UART_PARITY_NONE          // 奇偶校验位
    };

    // 串口针脚配置
    uart_pin_config_t pin_config = {
        .tx_pin = 0,                // 发送脚
        .rx_pin = 0,                // 接收脚
        .cts_pin = PIN_NONE,        // 发送就绪脚
        .rts_pin = PIN_NONE         // 接收就绪脚
    };
    
    // 先去初始化串口，参数为串口号
    uapi_uart_deinit(0);
    
    // 初始化串口
    // 参数：串口号，针脚配置，基本参数，高级参数，接收数据缓冲配置
    uapi_uart_init(0, &pin_config, &attr, NULL, &g_app_client_uart_buffer_config);
    
    // 注册接收回调函数
    // 参数：串口号，接收回调触发条件，size（如果触发条件涉及数据长度，则由该参数传入），接收回调函数
    // UART_RX_CONDITION_FULL_OR_IDLE 条件下，串口接收的字节数不能为16的整数倍，否则需要再发送一个字节的数据才能触发
    (void)uapi_uart_register_rx_callback(0, UART_RX_CONDITION_FULL_OR_IDLE,
                                     1, app_client_uart_rx_callback);
}


// 应用任务函数
static void LapCounterClientTask( char* arg)
{
    (void)arg;
    usleep(1000000); /* 延时1s，等待外设初始化完成 */
    
    // 初始化串口
    app_client_uart_init();
    
    //初始化 SLE
    app_client_sle_init();
    
    return NULL;
}


// 应用入口
static void LapCounterClientEntry(void)
{
    osThreadAttr_t attr;
    
    attr.name = "LapCounterClientThread";   /* 线程名称 */
    attr.attr_bits = 0U;                    /* 线程属性位，应为0 */
    attr.cb_mem = NULL;                     /* 线程控制块内存地址，NULL表示由OS自动分配 */
    attr.cb_size = 0U;                      /* 线程控制块大小，0表示由OS自动确定 */
    attr.stack_mem = NULL;                  /* 线程栈内存地址，NULL表示由OS自动分配 */
    attr.stack_size = 2048;                 /* 堆栈大小，单位字节 */
    attr.priority = 25;                     /* 线程优先级 */

    if (osThreadNew(LapCounterClientTask, NULL, &attr) == NULL) {
        printf("\r\n[%s] falied to create lap counter client task!\r\n", __func__);
    } else printf("\r\n[%s] create lap counter client successfully.\r\n", __func__);
        
}

SYS_RUN(LapCounterClientEntry); /* 注册应用入口 */
